package com.dylan.channel.v10.future;

import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.TimeoutException;

public class DefaultPromise<V> implements Promise<V> {

    volatile Object result;

    private static final Object SUCCESS = new Object();


    @Override
    public Promise<V> setSuccess(V result) {
        if (setSuccess0(result)) {
            //唤醒等待线程
            notifyAllWait();
            return this;
        }
        throw new RuntimeException("设置结果失败");
    }

    private synchronized void notifyAllWait() {
        this.notifyAll();
    }

    @Override
    public Promise<V> setSuccess() {
        return setSuccess(null);
    }

    private boolean setSuccess0(V result) {
        if (!isDone()) {
            this.result = result == null ? SUCCESS : result;
            return true;
        }
        return false;
    }

    @Override
    public Promise<V> sync() {
        return null;
    }

    @Override
    public Promise<V> await() {
        await0();
        return this;
    }

    private synchronized void await0() {
        try {
            this.wait();
        } catch (InterruptedException e) {
            throw new RuntimeException(e);
        }
    }

    @Override
    public boolean cancel(boolean mayInterruptIfRunning) {
        return false;
    }

    @Override
    public boolean isCancelled() {
        return false;
    }

    @Override
    public boolean isDone() {
        return result != null;
    }

    @Override
    public V get() throws InterruptedException, ExecutionException {
        if (isDone()) {
            return (V) result;
        }
        await();
        if (!isDone()) {
            throw new RuntimeException("虚假唤醒");
        }
        return (V) result;
    }

    @Override
    public V get(long timeout, TimeUnit unit) throws InterruptedException, ExecutionException, TimeoutException {
        if (!isDone()) {
            if (!await(timeout, unit)) {
                throw new TimeoutException();
            }
        }
        return (V) result;
    }

    @Override
    public boolean await(long timeout, TimeUnit unit) throws InterruptedException {
        return await0(unit.toNanos(timeout));
    }

    private boolean await0(long timeoutNanos) {
        final long startTime = System.nanoTime();
        synchronized (this) {
            try {
                long waitTime = timeoutNanos;
                while (!isDone() || waitTime > 0) {

                    this.wait(timeoutNanos);

                    waitTime = timeoutNanos - (System.nanoTime() - startTime);
                }
            } catch (InterruptedException e) {
                throw new RuntimeException(e);
            }
        }

        return false;
    }

    @Override
    public boolean isSuccess() {
        Object result = this.result;
        //result不为空，并且不等于被取消，并且不属于被包装过的异常类
        return result == SUCCESS;
    }
}
